from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import * 

import pandas as pd
from pathlib import Path
from chart.chart_generator import ChartGenerator

class ChartGenerationThread(QThread):
    data_processed = Signal(object, str, str)  # 发送处理后的数据、图表类型和数据类型

    def __init__(self, file_path, chart_type, data_type):
        super().__init__()
        self.file_path = file_path
        self.chart_type = chart_type
        self.data_type = data_type

    def run(self):
        try:
            # 根据文件扩展名读取数据
            file_extension = Path(self.file_path).suffix[1:].lower()
            if file_extension == 'csv':
                df = pd.read_csv(self.file_path)
            elif file_extension in ('xlsx', 'xls'):
                df = pd.read_excel(self.file_path)
            else:
                raise ValueError("不支持的文件类型")
                
            self.data_processed.emit(df, self.chart_type, self.data_type)
        except Exception as e:
            print(f"Error processing data: {str(e)}")
            self.data_processed.emit(None, self.chart_type, self.data_type)

# 在 AnalysisToolsController 类中新增图表控制器初始化
class AnalysisToolsController:
    def __init__(self, ui):
        self.ui = ui
        self.combo_box = None
        self.stacked_widget = None
        self.table_widget = None
        self.click_handler = ButtonClickHandler(self)
        self.init_controls()
        self.init_slot_btn()
        
        if self.stacked_widget:
            self.stacked_widget.setCurrentIndex(0)
            if self.combo_box:
                self.combo_box.setCurrentIndex(0)

    def init_controls(self):
        self.combo_box = self.ui.findChild(QComboBox, "comboBox_5")
        self.stacked_widget = self.ui.findChild(QStackedWidget, "stackedWidget_3")
        self.table_widget = self.ui.findChild(QTableWidget, "tableWidget_3")
        
        if self.stacked_widget and self.stacked_widget.count() > 0:
            self.stacked_widget.setCurrentIndex(0) 
        
        if self.combo_box:
            self.combo_box.currentIndexChanged.connect(self.switch_analysis_page)
        else:
            print("未找到comboBox_5")

    def init_slot_btn(self):
        btn_map = {
            'pushButton_5': self.click_handler.on_csv,
            'pushButton_6': self.click_handler.on_excel,
            'pushButton_7': self.click_handler.on_clear_tables,  
            'pushButton_9': self.click_handler.on_txt,
            'pushButton_10': self.click_handler.on_docx,
            'pushButton_11': self.click_handler.on_json,
            'pushButton_12': self.click_handler.on_clear_text,
            'pushButton_13': self.click_handler.on_generate_chart,
            'pushButton_20': self.click_handler.on_clear_chart,  
        }
        
        for btn_name, slot_func in btn_map.items():
            if btn := self.ui.findChild(QPushButton, btn_name):
                btn.clicked.connect(slot_func)
            else:
                print(f"未找到按钮 {btn_name}")

    @Slot(int)
    def switch_analysis_page(self, index):
        if self.stacked_widget:
            safe_index = max(0, min(index, self.stacked_widget.count()-1))
            self.stacked_widget.setCurrentIndex(safe_index)  
                
    def _updata_chart_button_state(self, text):
        """根据下拉框选项更新图表操作按钮状态"""
        is_chart_selected = text == "Chart"

        # 获取所有图表操作按钮
        chart_buttons = [
            'pushButton_13',
        ]

        for btn_name in chart_buttons:
            if btn := self.ui.findChild(QPushButton, btn_name):
                btn.setEnabled(True)
            
class ButtonClickHandler:
    def __init__(self, controller):
        self.controller = controller
        self.ui = controller.ui
        self.page_map = {
            'csv': 0,
            'excel': 1,
            'docx': 2,
            'txt': 3,
            'json': 4,
            'chart': 5 
        }
        self.control_map = {
            'csv': ('table', 'tableWidget_2'),
            'excel': ('table', 'tableWidget_3'),
            'docx': ('text', 'plainTextEdit_2'),
            'txt': ('text', 'plainTextEdit_4'),
            'json': ('text', 'plainTextEdit_3'),
            'chart': ('graphics', 'graphicsView')
        }

        self.current_chart_canvas = None

    @Slot()
    def on_csv(self): self._handle_import('csv', "CSV Files (*.csv)")
    @Slot()
    def on_excel(self): self._handle_import('excel', "Excel Files (*.xlsx *.xls)")
    @Slot()
    def on_docx(self): self._handle_import('docx', "Word Files (*.docx)")
    @Slot()
    def on_txt(self): self._handle_import('txt', "Text Files (*.txt)")
    @Slot()
    def on_json(self): self._handle_import('json', "JSON Files (*.json)")
    @Slot()
    def on_clear_text(self):
        """清空文本类型界面内容"""
        target_controls = {
            'docx': 'plainTextEdit_2',
            'txt': 'plainTextEdit_4',
            'json': 'plainTextEdit_3'
        }
        cleared = False
        try:
            for ctrl_name in target_controls.values():
                if text_edit := self.ui.findChild(QPlainTextEdit, ctrl_name):
                    text_edit.clear()
                    cleared = True
            
            if cleared:
                QMessageBox.information(None, "清除成功", 
                    "已清空JSON/TXT/DOCX界面内容", 
                    QMessageBox.StandardButton.Ok)
            else:
                QMessageBox.warning(None, "无内容可清除", 
                    "未找到可清除的文本控件", 
                    QMessageBox.StandardButton.Ok)
                
        except Exception as e:
            QMessageBox.critical(None, "清除失败", 
                f"操作失败：{str(e)}", 
                QMessageBox.StandardButton.Ok)
    @Slot()
    def on_clear_tables(self):
        """清空CSV/Excel表格内容"""
        try:
            # 获取当前页面类型
            current_index = self.controller.stacked_widget.currentIndex()
            current_type = [k for k,v in self.page_map.items() if v == current_index][0]
            
            # 从control_map获取对应控件名
            ctrl_type, ctrl_name = self.control_map[current_type]
            
            if table := self.ui.findChild(QTableWidget, ctrl_name):
                table.clearContents()
                table.setRowCount(0)
                table.setColumnCount(0)
                QMessageBox.information(None, "清除成功", 
                    f"已清空{current_type.upper()}表格内容", 
                    QMessageBox.StandardButton.Ok)
            else:
                QMessageBox.warning(None, "控件缺失",
                    f"未找到{current_type.upper()}表格控件",
                    QMessageBox.StandardButton.Ok)
                    
        except Exception as e:
            QMessageBox.critical(None, "清除失败", 
                f"操作失败：{str(e)}", 
                QMessageBox.StandardButton.Ok)
                
    @Slot()
    def on_generate_chart(self):
        try:
            chart_type = self._getcombo_value("comboBox")
            data_type = self._getcombo_value("comboBox_5")

            if not chart_type or not data_type:
                raise ValueError("请先选择图表类型")
            
            file_path, _ = QFileDialog.getOpenFileName(
                None, 
                "选择数据文件",
                str(Path.home()),
                "Data Files (*.csv *.xlsx *.xls);;All Files (*.*)"
            )
            if not file_path:
                return
            
            # 创建并启动线程
            self.chart_thread = ChartGenerationThread(file_path, chart_type, data_type)
            self.chart_thread.data_processed.connect(self._on_data_processed)
            self.chart_thread.start()
        
        except Exception as e:
            QMessageBox.critical(None, "错误", str(e), QMessageBox.StandardButton.Ok)
            
    def _on_data_processed(self, df, chart_type, data_type):
        if df is not None:
            try:
                # 在主线程中生成图表
                canvas = ChartGenerator.generate_chart_from_df(df, chart_type, data_type)

                # 清除旧图表
                self._clear_existing_chart()

                # 显示新图表
                graphics_view = self.ui.findChild(QGraphicsView, "graphicsView")
                if graphics_view:
                    self.current_chart_canvas = canvas
                    graphics_view.setScene(QGraphicsScene())
                    graphics_view.scene().addWidget(canvas)
                    graphics_view.show()
                    QMessageBox.information(None, "成功", "图表已生成", QMessageBox.StandardButton.Ok)
                else:
                    raise RuntimeError("未找到图表显示区域")
            
            except Exception as e:
                QMessageBox.critical(None, "错误", f"图表生成失败: {str(e)}", QMessageBox.StandardButton.Ok)
        else:
            QMessageBox.critical(None, "错误", "数据处理失败, 请选择图表类型", QMessageBox.StandardButton.Ok)
    
    def _handle_import(self, file_type, file_filter):
        """统一处理导入逻辑"""
        if not self._check_page(file_type):
            return
            
        control = self._get_control(file_type)
        if not control:
            return
            
        if path := self._get_file_path(file_type, file_filter):
            try:
                content = self._read_file(file_type, path)
                self._update_ui(file_type, control, content)
                self._show_message("导入成功", f"{file_type.upper()}文件导入成功")
            except Exception as e:
                self._show_message("导入失败", f"错误：{str(e)}", is_error=True)

    def _check_page(self, file_type):
        current_idx = self.controller.stacked_widget.currentIndex()
        if current_idx != self.page_map[file_type]:
            self._show_message("操作禁止", 
                f"请切换到{file_type.upper()}分析界面！当前索引：{current_idx}")
            return False
        return True

    def _get_control(self, file_type):
        ctrl_type, ctrl_name = self.control_map[file_type]
        control = self.ui.findChild(
            QTableWidget if ctrl_type == 'table' else QPlainTextEdit, 
            ctrl_name
        )
        if not control:
            self._show_message("控件缺失", f"未找到{ctrl_name}控件", is_error=True)
        return control

    def _get_file_path(self, file_type, filter_str):
        return QFileDialog.getOpenFileName(
            None,
            f"选择{file_type.upper()}文件",
            "",
            f"{filter_str};;All Files (*)"
        )[0]

    def _read_file(self, file_type, path):
        if file_type == 'csv':
            return pd.read_csv(path)
        elif file_type == 'excel':
            return pd.read_excel(path)
        elif file_type == 'docx':
            from docx import Document
            return "\n".join([p.text for p in Document(path).paragraphs if p.text.strip()])
        elif file_type == 'txt':
            with open(path, 'r', encoding='utf-8') as f:
                return f.read()
        elif file_type == 'json':
            import json
            with open(path, 'r', encoding='utf-8') as f:
                return json.dumps(json.load(f), indent=2, ensure_ascii=False)

    def _update_ui(self, file_type, control, content):
        if isinstance(control, QTableWidget):
            control.clear()
            if file_type in ['csv', 'excel']:
                control.setRowCount(content.shape[0])
                control.setColumnCount(content.shape[1])
                control.setHorizontalHeaderLabels(content.columns.astype(str))
                for row in range(content.shape[0]):
                    for col in range(content.shape[1]):
                        control.setItem(row, col, QTableWidgetItem(str(content.iat[row, col])))
        else:
            control.setPlainText(content)

    def _show_message(self, title, message, is_error=False):
        (QMessageBox.critical if is_error else QMessageBox.information)(
            None, title, message, QMessageBox.StandardButton.Ok)


    def _getcombo_value(self, combo_name):
        """安全获取下拉框值"""
        combo = self.ui.findChild(QComboBox, combo_name)
        return combo.currentText() if combo else ""
    
    def _clear_existing_chart(self):
        """清除现有图表"""
        if self.current_chart_canvas:
            self.current_chart_canvas.close()
            self.current_chart_canvas = None

    @Slot()
    def on_clear_chart(self):
        """清空图表内容"""
        try:
            self._clear_existing_chart()
            graphics_view = self.ui.findChild(QGraphicsView, "graphicsView")
            if graphics_view:
                graphics_view.scene().clear()  # 清空场景内容
                QMessageBox.information(None, "清除成功", 
                    "图表内容已清空", 
                    QMessageBox.StandardButton.Ok)
            else:
                QMessageBox.warning(None, "控件缺失",
                    "未找到图表显示区域",
                    QMessageBox.StandardButton.Ok)
        except Exception as e:
            QMessageBox.critical(None, "清除失败", 
                f"操作失败：{str(e)}", 
                QMessageBox.StandardButton.Ok)